﻿namespace EFS.RC.CC.Applications.EndPoints.OfficeService
{
	/// <summary>
	/// Customer end point
	/// </summary>
	internal class Customers : EFS.RC.CC.Applications.EndPoints.Presence<EFS.RC.CC.Deployment.Entities.EndPoints.Customer, EFS.RC.CC.Presences.EndPoints.OfficeService.Customer>
	{
		#region Composition
			
		// Distribution
		private EFS.RC.CC.Presences.Operators.Distribution.List agentsDistribution = null;

		#endregion

		#region Constructor

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="ownerUri"></param>
		public Customers(
			Microsoft.Rtc.Collaboration.ApplicationEndpointSettings applicationEndpointSettings,
			EFS.RC.CC.Presences.EndPoints.OfficeService.Customer customersEndPointPresence)
			: base(applicationEndpointSettings, customersEndPointPresence)
		{
			// distribution
			EFS.Common.Verify.Reference(applicationEndpointSettings, "applicationEndpointSettings");
			
			// make distribution
			agentsDistribution = new EFS.RC.CC.Presences.Operators.Distribution.List(this);
		}

		#endregion

		#region Usage

		/// <summary>
		/// Describe this object
		/// </summary>
		/// <returns></returns>
		public override System.String Describe()
		{
			return System.String.Format("EFS.RC.CC.Applications.EndPoints.OfficeService.Customers [{0}]", base.Describe());
		}

		/// <summary>
		/// Agents end point
		/// </summary>
		public EFS.RC.CC.Applications.EndPoints.OfficeService.Operators OfficeServiceOperatorsEndPointApplication
		{
			get
			{
				// presence knows operators presence as well
				return ApplicationPresence.EndPointsPresencesRegistrar.OperatorOfficeServiceEndPointPresence.PresenceEndPointApplication;
			}
		}

		/// <summary>
		/// Distribution
		/// </summary>
		public EFS.RC.CC.Presences.Operators.Distribution.List AgentsDistribution
		{
			get
			{
				// get distrubution
				return agentsDistribution;
			}
		}

		/// <summary>
		/// Deployment reload
		/// </summary>
		/// <returns></returns>
		public void ReloadDeployment()
		{
			// log
			EFS.EventLog.Log.LogInfo("ReloadDeployment", this);

			try
			{
				// reload deployment
				EFS.RC.CC.Deployment.Entities.EndPoints.Customer customerEndPointDeployment = EFS.RC.CC.Deployment.Tables.Tools.CustomerEndPoints.GetByID(ApplicationPresence.PresenceEndPointDeployment.ID.Value);
				
				// check if found
				EFS.Common.Verify.Reference(customerEndPointDeployment, 
					"Customer End Point Deployment no longer found in CC Database");

				// check uri
				EFS.Common.Verify.Condition(EFS.RC.Common.Utilities.SipUriCompare(ApplicationPresence.PresenceEndPointDeployment.URI, customerEndPointDeployment.URI),
					"Customer End Point Deployment URI had changed");

				// check office
				EFS.Common.Verify.Condition(ApplicationPresence.PresenceEndPointDeployment.OfficeEndPointID.Value == customerEndPointDeployment.OfficeEndPointID.Value,
					"Customer End Point Deployment Office had changed");

				// get skill
				ApplicationPresence.PresenceEndPointDeployment.SkillID = customerEndPointDeployment.SkillID;
			}
			catch (System.Exception ex)
			{
				// handle exception
				HandleExceptionSafe(ex);
			}
		}

		#endregion

		#region Startup

		/// <summary>
		/// End point active
		/// </summary>
		protected override void PostEndPointEstablish(Microsoft.Rtc.Collaboration.ApplicationEndpoint collaborationApplicationEndpoint)
		{
			// log
			EFS.EventLog.Log.LogInfo("PostEndPointEstablish", this);

			// check
			EFS.Common.Verify.Reference(collaborationApplicationEndpoint, "collaborationApplicationEndpoint");

			// register for audio/video calls
			collaborationApplicationEndpoint.RegisterForIncomingCall<Microsoft.Rtc.Collaboration.AudioVideo.AudioVideoCall>(OnIncomingAudioVideoCallCalls);
			
			// load distribution
            agentsDistribution.LoadInitialDistribution();
		}

		#endregion

		#region Runtime

		/// <summary>
		/// On incomming audio-video calls
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="args"></param>
		private void OnIncomingAudioVideoCallCalls(object sender, Microsoft.Rtc.Collaboration.CallReceivedEventArgs<Microsoft.Rtc.Collaboration.AudioVideo.AudioVideoCall> args)
		{
			// log
			EFS.EventLog.Log.LogInfo(System.String.Format("OnIncomingAudioVideoCallCalls {0}", args.RemoteParticipant.Uri), this);

			try
			{
				// SAL
				EFS.RC.CC.Tools.Loggers.SAL.Add(null, "OnIncomingAudioVideoCallCalls", args.RemoteParticipant.Uri, this);

				// Check if call is dialng out from conference
				if (args.IsConferenceDialOut)
				{
					// log
					EFS.EventLog.Log.LogInfo(System.String.Format("OnIncomingAudioVideoCallCalls Conference Dial Out {0}", args.RemoteParticipant.Uri), this);

					// check if call is for monitoring
					if (args.Call.Conversation.ApplicationContext is EFS.RC.CC.Sessions.OfficeService.Operators.Supervisors.Monitoring)
					{
						// log
						EFS.EventLog.Log.LogInfo(System.String.Format("OnIncomingAudioVideoCallCalls Conference Dial Out {0} ApplicationContext is EFS.RC.CC.Sessions.OfficeService.Operators.Supervisors.Monitoring", args.RemoteParticipant.Uri), this);

						// pass the call to session
						(args.Call.Conversation.ApplicationContext as EFS.RC.CC.Sessions.OfficeService.Operators.Supervisors.Monitoring).HandleIncommingCall(args.Call);
					}
					// check if call is for dial out
					else if (args.Call.Conversation.ApplicationContext is EFS.RC.CC.Sessions.OfficeService.Customers.DialOut)
					{
						EFS.EventLog.Log.LogInfo(System.String.Format("OnIncomingAudioVideoCallCalls Conference Dial Out {0} ApplicationContext is EFS.RC.CC.Sessions.OfficeService.Customers.DialOut", args.RemoteParticipant.Uri), this);

						// pass the call to session
						(args.Call.Conversation.ApplicationContext as EFS.RC.CC.Sessions.OfficeService.Customers.DialOut).HandleIncommingCall(args.Call);
					}
                    // check if call is for operator Ddi
					else if (args.Call.Conversation.ApplicationContext is EFS.RC.CC.Sessions.OfficeService.Operators.DialIn)
					{
						EFS.EventLog.Log.LogInfo(System.String.Format("OnIncomingAudioVideoCallCalls Conference Dial Out {0} ApplicationContext is EFS.RC.CC.Sessions.PublicOfficeService.Customers.DialOut", args.RemoteParticipant.Uri), this);

						if (args.CallToBeReplaced != null)
						{
							// pass the call to session
							(args.Call.Conversation.ApplicationContext as EFS.RC.CC.Sessions.OfficeService.Operators.DialIn).HandleReplacedCall(args.Call);
						}
						else
						{
							// pass the call to session
							(args.Call.Conversation.ApplicationContext as EFS.RC.CC.Sessions.OfficeService.Operators.DialIn).HandleIncommingCall(args.Call);
						}
					}
					else
					{
						// log
						EFS.EventLog.Log.LogInfo(System.String.Format("OnIncomingAudioVideoCallCalls Call not handled {0}", args.RemoteParticipant.Uri), this);

						// decline call
						args.Call.Decline();
					}
				}
				// Must be new call (customer)
				else if (args.IsNewConversation && args.CallToBeReplaced == null)
				{
					// log
					EFS.EventLog.Log.LogInfo(System.String.Format("OnIncomingAudioVideoCallCalls New Conversation no Replace {0}", args.RemoteParticipant.Uri), this);

					// customer session
					EFS.RC.CC.Sessions.OfficeService.Customers.Customer customerSession = new EFS.RC.CC.Sessions.OfficeService.Customers.HuntQueue.DialIn(this, args.Call, args.RequestData.FromHeader);

					// start session
					customerSession.BeginStartup();
				}
				// Must be new call (customer)
				else if (args.IsNewConversation && args.CallToBeReplaced != null)
				{
					// log
					EFS.EventLog.Log.LogInfo(System.String.Format("OnIncomingAudioVideoCallCalls New Conversation with Replace {0}", args.RemoteParticipant.Uri), this);

					// check if call is for group call
					if (args.CallToBeReplaced.Conversation.ApplicationContext is EFS.RC.CC.Tools.Hunters.Group)
					{
						// pass the call to session
						(args.CallToBeReplaced.Conversation.ApplicationContext as EFS.RC.CC.Tools.Hunters.Group).HandleReplacedCall(args.Call);
					}
					// check if call is ddi 
					else if (args.CallToBeReplaced.Conversation.ApplicationContext is EFS.RC.CC.Sessions.OfficeService.Operators.DialIn)
					{
						// pass the call to session
						(args.CallToBeReplaced.Conversation.ApplicationContext as EFS.RC.CC.Sessions.OfficeService.Operators.DialIn).HandleReplacedCall(args.Call);
					}
					// check if call is ddi 
					else if (args.CallToBeReplaced.Conversation.ApplicationContext is EFS.RC.CC.Sessions.OfficeService.Operators.Transfer)
					{
						// pass the call to session
						(args.CallToBeReplaced.Conversation.ApplicationContext as EFS.RC.CC.Sessions.OfficeService.Operators.Transfer).HandleReplacedCall(args.Call);
					}
					else
					{
						// log
						EFS.EventLog.Log.LogInfo(System.String.Format("OnIncomingAudioVideoCallCalls Call not handled {0}", args.RemoteParticipant.Uri), this);

						// decline call
						args.Call.Decline();
					}
				}
				else
				{
					// log
					EFS.EventLog.Log.LogInfo(System.String.Format("OnIncomingAudioVideoCallCalls Call not handled {0}", args.RemoteParticipant.Uri), this);

					// decline call
					args.Call.Decline();
				}
			}
			catch (System.Exception ex)
			{
				// log
				EFS.EventLog.Log.LogException(ex, this);

				try
				{
					// decline call
					args.Call.Decline();
				}
				catch (System.Exception ex1)
				{
					// log
					EFS.EventLog.Log.LogException(ex1, this);
				}
			}
		}

		#endregion

		#region Shutdown

		/// <summary>
		/// Clean-up 
		/// </summary>
		/// <param name="collaborationApplicationEndpoint"></param>
		protected override void PreEndPointTerminate(Microsoft.Rtc.Collaboration.ApplicationEndpoint collaborationApplicationEndpoint)
		{
			// log
			EFS.EventLog.Log.LogInfo("PreEndPointTerminate", this);

			// check
			EFS.Common.Verify.Reference(collaborationApplicationEndpoint, "collaborationApplicationEndpoint");

			//unregister the events
			collaborationApplicationEndpoint.UnregisterForIncomingCall<Microsoft.Rtc.Collaboration.AudioVideo.AudioVideoCall>(OnIncomingAudioVideoCallCalls);
		}

		/// <summary>
		/// Stopped 
		/// </summary>
		/// <param name="collaborationApplicationEndpoint"></param>
		protected override void EndPointStopped()
		{
			// log
			EFS.EventLog.Log.LogInfo("EndPointStopped", this);
		}

		#endregion
	}
}
